package fi.pakkanen.yarpg.core;

/**
 * A position on a map.
 * 
 * @author pakkanen
 * 
 */
public final class Position {

	private final GameMap map;
	private final int x;
	private final int y;

	/**
	 * Create a position on the map.
	 * 
	 * @param x
	 *            the position on the x-axis
	 * @param y
	 *            the position on the y-axis
	 * @throws IllegalStateException
	 *             when no map is given or when the position is invalid on the
	 *             given map
	 */
	public Position(GameMap map, int x, int y) {

		if (map == null) {
			throw new IllegalStateException("Map is null");
		}

		this.map = map;
		this.x = x;
		this.y = y;
	}

	/**
	 * Get the map that this position belongs to.
	 * 
	 * @return the map
	 */
	public GameMap getMap() {
		return map;
	}

	/**
	 * The position on the x-axis.
	 * 
	 * @return the x position
	 */
	public int getX() {
		return x;
	}

	/**
	 * The position on the y-axis.
	 * 
	 * @return the y position
	 */
	public int getY() {
		return y;
	}

	/**
	 * Check whether this position is valid.
	 * 
	 * @return true when it is valid, false otherwise.
	 */
	protected boolean isValid() {
		return map.isPositionValid(this);
	}

	/**
	 * Check whether moving to the given position leads to a valid new position.
	 * 
	 * @param direction
	 *            the moving direction
	 * @return true when the new position is valid, false otherwise
	 */
	public boolean canMove(MovingDirection direction) {
		return direction.moveFrom(this).isValid();
	}

	/**
	 * Move a step into the given direction.
	 * 
	 * @param direction
	 *            the moving direction
	 * @return the new position when it is valid, the current position otherwise
	 * @see #canMove(MovingDirection)
	 */
	public Position move(MovingDirection direction) {
		Position targetPosition = direction.moveFrom(this);

		return targetPosition.isValid() ? targetPosition : this;
	}

	@Override
	public String toString() {
		return "Position[" + x + ", " + y + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((map == null) ? 0 : map.hashCode());
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		Position other = (Position) obj;
		if (map == null) {
			if (other.map != null) {
				return false;
			}
		} else if (!map.equals(other.map)) {
			return false;
		}
		if (x != other.x) {
			return false;
		}
		if (y != other.y) {
			return false;
		}
		return true;
	}
}
